﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Threading;
using System.Net;
using MediaPortal.GUI.Library;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Web;

namespace MediaPortal.Plugins.Trailers.Providers {
  public class YahooTrailers : TrailerProviderBase {
    #region Variables

    #region Yahoo Trailer Trailer Locations

    private const string RSSNewTrailers = @"http://rss.ent.yahoo.com/movies/newtrailers.xml";
    private const string RSSTopTrailers = @"http://rss.ent.yahoo.com/movies/top25trailers.xml";
    private const string RSSBoxOffice = @"http://rss.ent.yahoo.com/movies/boxoffice.xml";
    private const string RSSThisWeek = @"http://rss.ent.yahoo.com/movies/thisweek.xml";
    private const string RSSComing = @"http://rss.ent.yahoo.com/movies/upcoming.xml";

    private const string RSSDVDTopSeller = @"http://rss.movies.yahoo.com/dvd/topsellers.xml";
    private const string RSSDVDNewNow = @"http://rss.movies.yahoo.com/dvd/newthisweek.xml";
    private const string RSSDVDNewNext = @"http://rss.movies.yahoo.com/dvd/newnextweek.xml";
    private const string RSSDVDPreorder = @"http://rss.ent.yahoo.com/movies/dvd/preorders.xml";

    #endregion

    #endregion

    #region TrailerProviderBase overrides

    public override string ProviderId() {
      return "3";
    }

    public override string ProviderName() {
      return "Yahoo Movie Trailers";
    }

    public override string ProviderImage() {
      return "";
    }

    public override Index GetIndex() {
      Index rtIndex = new Index();
      rtIndex.Add(new IndexItem("Just Added", RSSNewTrailers, true));
      rtIndex.Add(new IndexItem("Most Watched", RSSTopTrailers, true));
      rtIndex.Add(new IndexItem("Box Office", RSSBoxOffice, true));
      rtIndex.Add(new IndexItem("Opening This Week", RSSThisWeek, true));
      rtIndex.Add(new IndexItem("Coming Soon", RSSComing, true));
      rtIndex.Add(new IndexItem("Top Selling DVDs", RSSDVDTopSeller, true));
      rtIndex.Add(new IndexItem("New to DVD", RSSDVDNewNow, true));
      rtIndex.Add(new IndexItem("Next Week on DVD", RSSDVDNewNext, true));
      rtIndex.Add(new IndexItem("DVDs for Pre-Order", RSSDVDPreorder, true));

      return rtIndex;
    }

    public override Index GetIndex(string key) {
      Log.Info("[MyTrailers][Yahoo Trailers] Retrieving index: {0}", key);
      return GetYahooTrailersRSS(key);
    }

    public override Trailer GetDetails(string key) {
      Log.Info("[MyTrailers][Yahoo Trailers] Retrieving details: {0}", key);
      return GetMovieDetails(key);
    }

    #endregion


    public Trailer GetMovieDetails(string url) {
      string TempHTML = "";
      Trailer trailer = new Trailer();

      if (url.IndexOf("video") != -1 == true) { url = url.Replace("video", "details"); }

      GetWebPage(url, out TempHTML);

      if (TempHTML == null || TempHTML == string.Empty)
        return trailer;

      //GetTitle
      trailer.Title = Regex.Match(TempHTML, @"<h1><strong>(?<itemTitle>.*)</str").Groups["itemTitle"].Value.ToString();

      // Get PosterUrl
      Match m = Regex.Match(TempHTML, @"<img\ssrc=(?<posterurl>.*).jpg");
      trailer.Poster = m.Groups["posterurl"].Value + ".jpg";
      trailer.Thumb = m.Groups["posterurl"].Value + ".jpg";
      // If Cover is TV-serie example Desperate Housewives
      if (trailer.Poster.Equals("") == true)
      {
          Match p = Regex.Match(TempHTML, @"<img\ssrc=(?<posterurl>http://shopping.yahoo.com/video/images/muze/dvd.*.jpg)");
          trailer.Poster = p.Groups["posterurl"].Value + ".jpg";
          trailer.Thumb = p.Groups["posterurl"].Value + ".jpg";
      }
      // Get MoviePlot
      trailer.Description = Regex.Match(TempHTML, @"(.*\.\.\.)&nbsp").Groups[1].Value.ToString();
      if (trailer.Description == string.Empty) {
        int EP = TempHTML.IndexOf("<br clear=\"all\"");
        int BP = TempHTML.LastIndexOf("size=-1>", EP) + 8;
        int TP = EP - BP;
        trailer.Description = TempHTML.Substring(BP, TP);
        trailer.Description = trailer.Description.Replace("</font>", "");
      }

      // Get Genre
      if (Regex.Match(TempHTML, @"<!--\sno\sresult\sfor\sGenres\s-->").Success == false) {
        string tmpGenre = Regex.Match(TempHTML, @"(?isx-mn:genres:.*?size=-1>(.*?)</font)").Groups[1].Value.ToString();
        if (tmpGenre.Contains("and") == true) {
          tmpGenre.Replace("and", ",");
          tmpGenre.Replace(" ", "");
          string[] genreList = tmpGenre.Split(new char[] { ',' });
          foreach (string genre in genreList) {
            trailer.Genres.Add(genre);
          }
        }
        else {
          trailer.Genres.Add(tmpGenre);
        }
      }


      // Get Runtime
      if (Regex.Match(TempHTML, @"<!--\sno\sresult\sfor\sRunning\sTime\s-->").Success == false) {
        string tmpRuntime = Regex.Match(TempHTML, @"(?isx-mn:Running\sTime:.*?size=-1>(.*?)</font)").Groups[1].Value.ToString();
        int runHour = Int16.Parse(Regex.Match(tmpRuntime, @"(?<hours>\d*).hr").Groups["hours"].Value);
        int runMin = Int16.Parse(Regex.Match(tmpRuntime, @"(?<min>\d*).min").Groups["min"].Value);
        trailer.Runtime = runHour * 60 + runMin;
        Log.Debug("[MyTrailers][Yahoo Trailers]: Movie: {0}: RunTime: {1}", trailer.Title, trailer.Runtime.ToString());
      }


      // Get ReleaseDate
      if (Regex.Match(TempHTML, @"<!--\sno\sresult\sfor\sRelease\sDate\s-->").Success == false) {
        string tmpReleaseDate = Regex.Match(TempHTML, @"(?isx-mn:Release\sDate:.*?size=-1>(.*?)</font)").Groups[1].Value.ToString();
        if (tmpReleaseDate.Contains(" (wide)") == true) {
          tmpReleaseDate = tmpReleaseDate.Replace(" (wide)", "");
        }
        if (tmpReleaseDate.Contains(" (limited)") == true) {
          tmpReleaseDate = tmpReleaseDate.Replace(" (limited)", "");
        }
        string dateEnd = Regex.Match(tmpReleaseDate, @"\s\d*(?<dateEnd>.*),").Groups["dateEnd"].Value;
        tmpReleaseDate = tmpReleaseDate.Replace(dateEnd, "");
        DateTime tmpDate;
        if (DateTime.TryParse(tmpReleaseDate, out tmpDate))
          trailer.ReleaseDate = tmpDate;
        Log.Debug("[MyTrailers][Yahoo Trailers]: Movie: {0}: RunTime: {1} Converted Runtime: {2}", trailer.Title, tmpReleaseDate, trailer.ReleaseDate.ToShortDateString());
      }
        //Go grab VideoCollection for Movie
        string trailersURL = url.Replace("details", "video");
        trailer.Media = GetMovieTrailers(trailersURL, trailer);

      string casturl = url.Replace("details", "cast");
      GetWebPage(casturl, out TempHTML);

      MatchCollection mc = Regex.Matches(TempHTML, @"contributor.*>(?<clipCast>.*)..a>");
      int cstMtch = 0;
      foreach (Match mtch in mc)
      {
          if (cstMtch < 6 == true)
          {
              trailer.Cast.Add(mtch.Groups["clipCast"].Value);
              ++cstMtch;
          }
      }

      // Get Rating
      if (url.IndexOf("details") != -1 == true) { url = url.Replace("details", "info"); }

      GetWebPage(url, out TempHTML);

      Match r = Regex.Match(TempHTML, "class=.ratingRating.>\n(?<clipRating>.*)..div");
      if (r.Groups["clipRating"].Value == "") {
        r = Regex.Match(TempHTML, @"class=.movie.critics.rating..(?<clipRating>.*)..b><");
      }

      if (r.Groups["clipRating"].Value == "" == false) {
        switch (r.Groups["clipRating"].Value) {
          case "A+":
            trailer.Rating = "10";
            break;
          case "A":
            trailer.Rating = "9";
            break;
          case "A-":
            trailer.Rating = "8.5";
            break;
          case "B+":
            trailer.Rating = "8";
            break;
          case "B":
            trailer.Rating = "7";
            break;
          case "B-":
            trailer.Rating = "6.5";
            break;
          case "C+":
            trailer.Rating = "6";
            break;
          case "C":
            trailer.Rating = "5";
            break;
          case "C-":
            trailer.Rating = "4.5";
            break;
          case "D+":
            trailer.Rating = "4";
            break;
          case "D":
            trailer.Rating = "3";
            break;
          case "D-":
            trailer.Rating = "2.5";
            break;
          case "F":
            trailer.Rating = "1";
            break;
        }
        Log.Debug("[MyTrailers][Yahoo Trailers]: Movie: {0}: Rating: {1}", trailer.Title, trailer.Rating);
      }
      return trailer;
    }

    public VideoCollection GetMovieTrailers(string url, Trailer trailer)
    {
        Log.Debug("[MyTrailers][Yahoo Trailers]: Attempting to grab trailers for {0}", trailer.Title);
        VideoCollection videos = new VideoCollection();
        string TempHTML;
        GetWebPage(url, out TempHTML);


        if (TempHTML == null || TempHTML == string.Empty)
            return videos;

        MatchCollection mc = Regex.Matches(TempHTML, @"(?sx-m).*?(?:</tr>)");

        foreach (Match m in mc)
        {
            // get trailers & teasers can be more then 1
            if (m.Value.IndexOf("title") != -1)
            {
                Match m1 = Regex.Match(m.Value, @".*id=.clipTitle.*clipTitle(?<clipID>.*).clip.*>(?<clipTitle>.*)</a");
                string titleClip = m1.Groups["clipTitle"].Value;
                if (m1.Groups["clipID"].Value == "" == false)
                {
                    Video video = new Video(HttpUtility.HtmlDecode(titleClip));
                    Uri clipURI = new Uri(@"http://cosmos.bcst.yahoo.com/up/player/process/qtlHD.qtl?node_id=" + m1.Groups["clipID"].Value);
                    video.Size[VideoQuality.UNKNOWN] = clipURI;
                    Log.Debug("[MyTrailers][Yahoo Trailers]: Clip found for {0}. Clip Title: {1}, Clip Link: {2}", trailer.Title, video.Label, clipURI.ToString());
                    videos.Add(video);
                }
            }
        }
        return videos;
    }

    private Index GetYahooTrailersRSS(string xmlurl) {
      Index items = new Index();
      string TempXML;

      GetWebPage(xmlurl, out TempXML);

      if (TempXML == null || TempXML == string.Empty)
        return items;

      XmlDocument XmlDoc = new XmlDocument();
      XmlDoc.LoadXml(TempXML);
      XmlNodeList MovieTitle = XmlDoc.SelectNodes("/rss/channel/item/title");
      XmlNodeList MovieLink = XmlDoc.SelectNodes("/rss/channel/item/link");
      if (MovieTitle == null)
        return items;
      string url = "";
      for (int i = 0; i < MovieTitle.Count; i++) {
        IndexItem item = new IndexItem();
        Trailer trail = new Trailer();
        item.Label = MovieTitle[i].InnerText;

        Byte[] encodedBytes = Encoding.ASCII.GetBytes(MovieLink[i].InnerText);
        url = Encoding.ASCII.GetString(encodedBytes);
        if (url.StartsWith("/") == true)
          url = url.Remove(0, 1);
        if (url.StartsWith("http://") == false)
          url = "http://movies.yahoo.com/" + url;
        if (url.Contains("trailer") == false)
          url = url.Replace("info", "trailer");
        if (url.Contains("trailer") == true)
          url = url.Replace("trailer", "video");
        if (url.IndexOf(@"/rss/dvd/") != -1 == true) {
          Match id = Regex.Match(url, @"&id.(?<showID>.*)");
          StringBuilder sb = new StringBuilder();
          sb.Append("http://movies.yahoo.com/movie/");
          sb.Append(id.Groups["showID"].Value);
          sb.Append("/video");
          url = sb.ToString();
        }
        item.Key = url;
        items.Add(item);
      }
      return items;
    }


    public void GetWebPage(string url, out string HTMLDownload) // Get url and put in string
    {
      HTMLDownload = string.Empty;

      WebClient wc = new WebClient();
      wc.Headers.Add("referer", @"http://movies.yahoo.com/");

      try {
        byte[] HTMLBuffer;
        HTMLBuffer = wc.DownloadData(url);
        HTMLDownload = Encoding.UTF8.GetString(HTMLBuffer);
      }
      catch (Exception ex) {
          Log.Info("[MyTrailers][Yahoo Trailers]: URL request exception {0}", ex.Message);
      }
      finally {
        wc.Dispose();
      }

      if (HTMLDownload == "" == true)
          Log.Debug("[MyTrailers][Yahoo Trailers]: URL returned nothing: {0}", url);
      else
          Log.Debug("[MyTrailers][Yahoo Trailers]: URL request successful: {0}", url);
    }

  }

}